import ipywidgets as widgets
from ipyniivue import NiiVue, download_dataset
from ipyniivue.download_dataset import DATA_FOLDER
# GitHub API URL for the base folder
BASE_API_URL = "https://niivue.com/demos/images/"
# Download data for example
download_dataset(
BASE_API_URL,
DATA_FOLDER,
files=[
"mni152.nii.gz",
"hippo.nii.gz",
"pcasl.nii.gz",
],
)
mni152.nii.gz already exists. hippo.nii.gz already exists. pcasl.nii.gz already exists. Dataset downloaded successfully to /Users/chrisdrake/Dev/ipyniivue/src/ipyniivue/images.
Mosaic strings¶
Mosaic coordinates are preceded by one or more labels. The first label is orientation:
A: axial C: coronal S: sagittal
Numbers after the orientation label indicate slices in the real-world coordinate system, defined by the volume's affine transformation matrix. So the string:
A 10.0 20.4 30
would indicate axial slices at 10.0, 20.4, and 30 mm.
Additional labels may be used to render a volume (R) and to show the location of other slices in the mosaic (X). In the case of a volume render, the value of the coordinate is ignored and the sign indicates the view orientation.
This first example is based on https://niivue.github.io/niivue/features/mosaic.html¶
Note that this example does NOT show orientation labels, and L/R might not be what you expect.
volumes = [
{
"path": DATA_FOLDER / "mni152.nii.gz",
"colormap": "gray",
"visible": True,
"opacity": 1.0,
},
{
"path": DATA_FOLDER / "hippo.nii.gz",
"colormap": "red",
"visible": True,
"opacity": 1,
},
]
nv = NiiVue()
nv.load_volumes(volumes)
style = {"description_width": "initial"}
string_widget = widgets.Text(
value="A -20 50 60 70 C -10 -20 -50; S R X 0 R X -0",
description="Slice mosaic string",
style=style,
)
string_widget.layout.width = "auto"
nv.opts.slice_mosaic_string = string_widget.value
def update_view(*args):
"""Update the mosaic according to the string in the widget."""
nv.opts.slice_mosaic_string = string_widget.value
string_widget.observe(update_view, "value")
display(string_widget)
display(nv)
/Users/chrisdrake/Dev/ipyniivue/src/ipyniivue/widget.py:1327: UserWarning: Ignored unsupported kwargs in Volume: ['visible'] volume_objects.append(Volume(**item))
Full mosaic demo¶
For this, we'll use nibabel to get the dimensions of the volume we're looking at. Since nibabel isn't currently in the ipyniivue requirements, you might need to install it.
try:
import nibabel as nib
except ModuleNotFoundError:
!pip install nibabel
import nibabel as nib
import numpy as np
orientations = {"sagittal": 0, "coronal": 1, "axial": 2}
def get_coords(image_file):
"""Get coordinates for the slices in each orientation."""
img = nib.load(image_file)
coords = {}
for label, axis in orientations.items():
coords[label] = [
x * img.affine[axis][axis] + img.affine[axis][3]
for x in range(0, img.shape[axis])
]
return coords
def full_mosaic(coords, ncols=None, step=1, orientation="axial"):
"""
Generate a mosaic string.
Args:
coords: coordinates for the slices in each orientation
ncols: number of columns for display, default: sqrt of shape
step: display every Nth slice, default: 1
orientation: orientation of slices, should be in the orientations dict above
"""
prefix = orientation[0].upper()
if not ncols:
ncols = int(np.sqrt(len(coords[orientation])))
ms = ""
for i, x in enumerate(range(0, len(coords[orientation]), step)):
if not i % ncols:
if ms == "":
ms = ms + f"{prefix} "
else:
ms = ms + f"; {prefix} "
ms = ms + f"{coords[orientation][x]:.02f} "
return ms
# Putting it all together
# By default ipyniivue has a widget height = 300.
# We'll put that on a slider to let us adjust the image size.
t1_image_file = DATA_FOLDER / "mni152.nii.gz"
coords = get_coords(t1_image_file)
volumes = [
{
"path": t1_image_file,
"colormap": "gray",
"visible": True,
"opacity": 1.0,
},
]
nv2 = NiiVue()
nv2.load_volumes(volumes)
# Start by showing every 5th slice, with 10 columns
init_cols = 10
init_step = 5
nv2.opts.slice_mosaic_string = full_mosaic(coords, ncols=init_cols, step=init_step)
axis_selector = widgets.Dropdown(
options=["axial", "sagittal", "coronal"], description="View"
)
column_slider = widgets.IntSlider(min=0, max=20, value=init_cols, description="Columns")
step_slider = widgets.IntSlider(min=1, max=20, value=init_step, description="Steps")
size_slider = widgets.IntSlider(min=100, max=1000, value=300, description="Height")
def update_mosaic(*args):
"""Update the mosaic string."""
nv2.opts.slice_mosaic_string = full_mosaic(
coords,
step=step_slider.value,
ncols=column_slider.value,
orientation=axis_selector.value,
)
def update_height(*args):
"""Update widget height."""
nv2.height = size_slider.value
column_slider.observe(update_mosaic, "value")
step_slider.observe(update_mosaic, "value")
axis_selector.observe(update_mosaic, "value")
size_slider.observe(update_height, "value")
display(column_slider)
display(step_slider)
display(size_slider)
display(axis_selector)
display(nv2)
/Users/chrisdrake/Dev/ipyniivue/src/ipyniivue/widget.py:1327: UserWarning: Ignored unsupported kwargs in Volume: ['visible'] volume_objects.append(Volume(**item))
4D mosaic viewer¶
example4d = DATA_FOLDER / "pcasl.nii.gz"
coords4d = get_coords(example4d)
volumes = [
{
"path": example4d,
"colormap": "gray",
"visible": True,
"opacity": 1.0,
},
]
nv3 = NiiVue()
nv3.load_volumes(volumes)
nvols = nib.load(example4d).shape[-1]
init_cols = np.ceil(np.sqrt(nib.load(example4d).shape[2]))
nv3.opts.slice_mosaic_string = full_mosaic(coords4d, ncols=init_cols)
column_slider4d = widgets.IntSlider(
min=0, max=20, value=init_cols, description="Columns"
)
vol_slider4d = widgets.IntSlider(min=0, max=nvols - 1, description="Volume")
size_slider4d = widgets.IntSlider(min=100, max=1000, value=300, description="Height")
def update_mosaic4d(*args):
"""Update mosaic string."""
nv3.volumes[0].frame4D = vol_slider4d.value
nv3.opts.slice_mosaic_string = full_mosaic(coords4d, ncols=column_slider4d.value)
def update_view4d(*args):
"""Update widget height."""
nv3.height = size_slider4d.value
column_slider4d.observe(update_mosaic4d, "value")
vol_slider4d.observe(update_mosaic4d, "value")
size_slider4d.observe(update_view4d, "value")
display(column_slider4d)
display(vol_slider4d)
display(size_slider4d)
display(nv3)